###########################################################################
#	$Id: Engine.p 38 2008-09-10 10:36:17Z donbeave $
###########################################################################

@CLASS
Engine

@USE
Object.p
Lib.p

@BASE
Object


@auto[]
$self.NOW[^date::now[]]

$self.DOMAINS[^hash::create[]]
$self.SITES[^hash::create[]]
$self.LOCALES[^hash::create[]]
$self.TEMPLATES[^hash::create[]]
#end @auto[]



###########################################################################
#	Options:
#		== Object:create[]
#		$.DOMAIN[string] = $env:SERVER_NAME
#		$.REQUEST_URI[string] = $request:uri
#		$.TEMPLATES_PATH[string] = $ROOT_PATH/templates
#		$.PROCESSES_PATH[string] = $ROOT_PATH/processes
#		$.LANGUAGE[string]
#		$.MATCH_CASE(bool) = true
@create[hshParams][hParams;tDomains;tSites;tSiteLocales;tObjects;tObjectsTexts;tBlocks;tProcesses]
$hParams[^hash::create[$hshParams]]

$self.READY(true)

^BASE:create[$hParams]

^TABLES.add[
	$.domains[${TABLES_PREFIX}domains]
	$.sites[${TABLES_PREFIX}sites]
	$.locales[${TABLES_PREFIX}locales]
	$.locales_to_sites[${TABLES_PREFIX}locales_to_sites]
	$.locales_to_blocks[${TABLES_PREFIX}locales_to_blocks]
	$.templates[${TABLES_PREFIX}templates]
	$.templates_types[${TABLES_PREFIX}templates_types]
]


$self.DOMAIN_ID(0)
$self.SITE_ID(0)
$self.LOCALE_ID(0)


$self.ADDITIONAL_FIELDS[^table::create{select	update	field
main.site_id
main.template_id
main.url
main.link_to_object_type_id
main.link_to_object_id
main.path
main.full_path
main.nesting
}]

$self.TEXTS_ADDITIONAL_FIELDS[^table::create{select	update	field
main.window_name
main.document_name
main.is_published
}]


^if(def $hParams.DOMAIN && $hParams.DOMAIN is 'string'){
	$DOMAIN[^hParams.DOMAIN.trim[]]
}{
	$self.DOMAIN[$env:SERVER_NAME]
}

^if(def $hParams.REQUEST_URI){
	$REQUEST_URI[$hParams.REQUEST_URI]
}{
	$self.REQUEST_URI[$request:uri]
}

^if(def $hParams.ROOT_PATH){
	$ROOT_PATH[^bLib:preparePath[$hParams.ROOT_PATH]]
}{
	$self.ROOT_PATH[/../data]
}

^if(def $hParams.TEMPLATES_PATH){
	$TEMPLATES_PATH[^bLib:preparePath[$hParams.TEMPLATES_PATH]]
}{
	$TEMPLATES_PATH[$ROOT_PATH/templates]
}
^if(def $hParams.PROCESSES_PATH){
	$PROCESSES_PATH[^bLib:preparePath[$hParams.PROCESSES_PATH]]
}{
	$PROCESSES_PATH[$ROOT_PATH/processes]
}

^if(^hParams.MATCH_CASE.bool(true)){
	$self.MATCH_CASE(^hParams.MATCH_CASE.bool(true))
}


$tDomains[^self.getDomains[
#	$.add_to_hash(true)
]]

$self.DOMAIN_ID(^DOMAINS.[$DOMAIN].id.int(0))
$self.SITE_ID(^DOMAINS.[$DOMAIN].site_id.int(0))

^if($SITE_ID){
	$tSites[^self.getSites[
#		$.add_to_hash(true)
	]]
}{
	^throw[${CLASS_NAME}.search;^$SITE_ID (domain: $DOMAIN);site not found]
}


$tSiteLocales[^self.getLocales[
	$.site_id($SITE_ID)
#	$.add_to_hash(true)
]]

# determining site locale
^if(def $hParams.LANGUAGE){
	^if(^tSiteLocales.locate[language;$hParams.LANGUAGE]){
		$self.LOCALE_ID($tSiteLocales.id)
	}{
		^throw[${CLASS_NAME}.search;^$LOCALE_ID (lang: $hParams.LANGUAGE);site locale not found]
	}
}{
#	if not specified language, using default locale
	$self.LOCALE_ID(^SITES.[$SITE_ID].locale_id.int(0))
}


# setting charset used by locale
^if($LOCALES.[$LOCALE_ID]){
	$self.CHARSET[$LOCALES.[$LOCALE_ID].charset]
}{
#	^throw[${CLASS_NAME}.bind;(id: $LOCALE_ID);current locale not binded to site]
}


# getting root objects, global objects and object by requested URI
$tObjects[^self._getGeneralObjects[]]


#$self.CONTENT-TYPE[text/html]

# getting current object's ID
^if(
	($MATCH_CASE && (^tObjects.locate(^tObjects.full_path.lower[] eq ^REQUEST_URI.lower[])))
	||
	(!$MATCH_CASE && (^tObjects.locate($tObjects.full_path eq $REQUEST_URI)))
){
	$self.OBJECT_ID($tObjects.id)
	
	$self.INITIAL_OBJECT_ID($tObjects.id)
}{
	$iErrorObjectID($SITES.[$SITE_ID].error_object_id)
	
	^if(^iErrorObjectID.int(0)){
		^Lib:location[^taint[as-is][$OBJECTS.[^iErrorObjectID.int(0)].full_path]]
		
		$self.READY(false)
	}{
		^throw[${CLASS_NAME}.search;(uri: $REQUEST_URI);object not found]
	}
}


# trying to get text for object
$tObjectsTexts[^self.getObjectsTexts[
	$.ids[$tObjects]
	$.SQL_WHERE[
		main.locale_id = $LOCALE_ID OR
		main.locale_id = $SPECIAL_LOCALE
	]
#	$.add_to_hash(true)
]]


$tBlocks[^self.getBlocks[
	$.objects_ids[^tObjects.select($tObjects.hierarchy eq "current" || $tObjects.hierarchy eq "link" || $tObjects.hierarchy eq "global")]
]]


$tProcesses[^self.getProcesses[
#	$.add_to_hash(true)
]]


#$self.DATA_TYPES[^self.getDataTypes[]]
#end @create[]



###########################################################################
#	Options:
#		$.add_to_hash(bool) = true
#	Result: table
@getDomains[hshParams;hshSqlOptions;hshCacheOptions][hParams]
$hParams[^hash::create[$hshParams]]

$result[^SQL_OBJECT.table{
	SELECT
		domain_id AS id,
		site_id,
		name
	FROM
		$TABLES.domains
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]

^if($result && ^hParams.add_to_hash.bool(true)){
	^DOMAINS.add[^result.hash[name]]
}
#end @getDomains[]



###########################################################################
#	Options:
#		$.add_to_hash(bool) = true
#	Result: table
@getSites[hshParams;hshSqlOptions;hshCacheOptions][hParams]
$hParams[^hash::create[$hshParams]]

$result[^SQL_OBJECT.table{
	SELECT
		site_id AS id,
		locale_id,
		sort_order,
		error_object_id,
		name
	FROM
		$TABLES.sites
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]

^if($result && ^hParams.add_to_hash.bool(true)){
	^SITES.add[^result.hash[id]]
}
#end @getSites[]



###########################################################################
#	Options:
#		$.site_id(int)
#		$.add_to_hash(bool) = true
#	Result: table
@getLocales[hshParams;hshSqlOptions;hshCacheOptions][hParams]
$hParams[^hash::create[$hshParams]]

$result[^SQL_OBJECT.table{
	SELECT
		main.locale_id AS id,
		main.sort_order,
		main.language,
		main.name,
		main.charset
	FROM
		^if(^hParams.site_id.int(0)){
			$TABLES.locales_to_sites,
		}
		$TABLES.locales main
	WHERE
		^if(^hParams.site_id.int(0)){
			main.locale_id = ${TABLES.locales_to_sites}.locale_id AND
			${TABLES.locales_to_sites}.site_id = ^hParams.site_id.int(0) AND
		}
		1=1
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]

^if($result && ^hParams.add_to_hash.bool(true)){
	^LOCALES.add[^result.hash[id]]
}
#end @getLocales[]



###########################################################################
#	Options:
#		$.site_id(int)
#	== @BASE:getObjects[]
@getObjects[hshParams;hshSqlOptions;hshCacheOptions][hParams]
$hParams[^hash::create[$hshParams]]

^if(^hParams.site_id.int(0)){
	$hParams.SQL_WHERE[
		^if(def $hParams.SQL_WHERE){($hParams.SQL_WHERE) AND}
		main.site_id = ^hParams.site_id.int(0)
	]
}

^if(def $hParams.is_published){
	$hParams.SQL_FROM[
		objects_texts
		^if(def $hParams.SQL_FROM){, $hParams.SQL_FROM}
	]
	$hParams.SQL_WHERE[
		^if(def $hParams.SQL_WHERE){($hParams.SQL_WHERE) AND}
		(objects_texts.object_id = main.object_id AND
		objects_texts.is_published = 1)
	]
}

^if(^hParams.id.int(0)){
	$hParams.SQL_FROM[
		LEFT JOIN
			objects current
		ON (current.object_id = ^hParams.id.int(0))
	]
	
	$hParams.SQL_WHERE[
		^if(def $hParams.SQL_WHERE){($hParams.SQL_WHERE) AND}
		main.thread_id = current.thread_id
	]
	
	$hParams.id[]
}

^BASE:getObjects[$hParams;$hshSqlOptions;$hshCacheOptions]
#end @getObjects[]



###########################################################################
#	Options:
#		$.redirection(bool) = true
#	Result: string
@parseObject[intObjectID;hshParams][hParams;iPreviousObjectID;tObject]
$hParams[^hash::create[$hshParams]]

# if needed, changing current object
^if(^intObjectID.int($OBJECT_ID) != $OBJECT_ID){
	$iPreviousObjectID($OBJECT_ID)
	
	^self.replaceCurrentObject(^intObjectID.int($OBJECT_ID))
}

$tObject[$OBJECTS.[$OBJECT_ID]]

# if defined object's url, location to url
^if(def $tObject.url && ^hParams.redirection.bool(true)){
	^Lib:location[^taint[as-is][$tObject.url]]
}{
	$result[^BASE:parseObject[$OBJECT_ID]]
}

^if(^iPreviousObjectID.int(0)){
	^self.replaceCurrentObject(^iPreviousObjectID.int(0))
}
#end @parseObject[]



###########################################################################
#	Result: table
@_getGeneralObjects[hshParams][hParams;iErrorObject;tObjectsTypes;tGlobalTypes]
$hParams[^hash::create[$hshParams]]

$iErrorObject(^SITES.[$SITE_ID].error_object_id.int(0))

$tObjectsTypes[^self.getObjectsTypes[
#	$.add_to_hash(true)
]]

$tGlobalTypes[^tObjectsTypes.select($tObjectsTypes.name eq "global")]

$result[^self.getObjects[
	$.site_id($SITE_ID)
	$.is_published(true)
	$.SQL_SELECT[
		CASE
			WHEN main.object_id = current.object_id
			THEN "current"
			
			WHEN main.object_id IN (^tGlobalTypes.menu{$tGlobalTypes.id}[,])
			THEN "global"
			
			WHEN main.parent_id = 0
			THEN "root"
			
			WHEN main.nesting < current.nesting AND main.thread_id = current.thread_id
			THEN "parent"
			
			WHEN main.nesting > current.nesting AND main.thread_id = current.thread_id
			THEN "child" 
			
			WHEN main.object_id = $iErrorObject
			THEN "error"
			
			WHEN main.object_id = current.link_to_object_id
			THEN "link"
		END hierarchy
	]
	$.SQL_FROM[
		$TABLES.objects_types
		
		LEFT JOIN
			objects current
		ON (

			^if($MATCH_CASE){
				^SQL_OBJECT.lower[current.full_path] = '^REQUEST_URI.lower[]' AND
			}{
				current.full_path = '$REQUEST_URI' AND
			}
			
			current.object_type_id = ${TABLES.objects_types}.object_type_id AND
			${TABLES.objects_types}.is_fake = 0
		)
	]
	$.SQL_WHERE[
#		current thread's objects
		(main.thread_id = current.thread_id AND
		main.nesting <= current.nesting) OR
		(main.parent_id = current.object_id) OR
		
#		linked object
		main.object_id = current.link_to_object_id OR
		
#		root objects
		main.parent_id = 0 OR
		main.nesting = 1 OR
		
#		error object
		main.object_id = $iErrorObject OR
		
#		global objects
		main.object_id IN (^tGlobalTypes.menu{$tGlobalTypes.id}[,])
	]
	$.SQL_additional[GROUP BY id]
	$.add_to_hash[$hParams.add_to_hash]
]]
#end @_getGeneralObjects[]



###########################################################################
#	Parameters:
#		$.add_to_hash(bool) = true
#	Result: table
@getTemplates[hshParams;hshSqlOptions;hshCacheOptions][hParams]
$hParams[^hash::create[$hshParams]]

$result[^SQL_OBJECT.table{
	SELECT
		template_id AS id,
		sort_order,
		template_type_id AS type_id,
		dt_update,
		name,
		filename,
		params,
		description
	FROM
		$TABLES.templates
	$hParams.SQL_additional
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]

^if(^hParams.add_to_hash.bool(true)){
	^TEMPLATES.add[^result.hash[id]]
}
#end @getTemplates[]



###########################################################################
#	Result: table
@getTemplatesTypes[hshParams;hshSqlOptions;hshCacheOptions][hParams]
$hParams[^hash::create[$hshParams]]

$result[^SQL_OBJECT.table{
	SELECT
		template_type_id AS id,
		sort_order,
		name
	FROM
		$TABLES.templates_types
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]
#end @getTemplatesTypes[]



###########################################################################
#	Options:
#		$.data[string]
#		$.extra[string]
#		$.redirection(bool) = true
#		$.result[text]
#	Result: xdoc
@execute[hshParams][hParams;sObjectData;sContent;tGlobalBlocks]
$hParams[^hash::create[$hshParams]]

$sObjectData[^self.parseObject[;$.redirection($hParams.redirection)]]

^if(^PROCESS_HANDLED.bool(false)){
	$result[$sObjectData]
}{

	$sContent[$hParams.extra<document>
		<info>
			<date>^self.printDateTime[$NOW]</date>
			<charset request="$request:charset" response="$response:charset" />
			<domain id="$DOMAIN_ID" name="$DOMAIN" />
		</info>
		^self.printObject[$OBJECTS.[$OBJECT_ID]]
		$sObjectData

#		parsing global blocks
		$tGlobalObjects[^OBJECTS.table.select($OBJECTS.table.hierarchy eq "global")]

		^if($tGlobalObjects){
			<global>
				^tGlobalObjects.menu{
					^self.parseObject(^tGlobalObjects.id.int(0))
				}
			</global>
		}
		$hParams.data
	</document>]
	
	^if($hParams.result eq "text"){
		$result[$sContent]
	}{
		$result[^xdoc::create{$sContent}]
	}
}
#end @execute[]



###########################################################################
#	Result: xdoc
@transformDocument[xdcBody][iTemplateID;tTemplates;hXSLTParams]
^if(!($xdcBody is 'xdoc')){
	^throw[${CLASS_NAME}.type;^$xdcBody;type not supported]
}

$iTemplateID(^OBJECTS.[$OBJECT_ID].template_id.int(0))

^if(!$iTemplateID){
	^throw[${CLASS_NAME}.spec;object.template_id (obj: $OBJECT_ID);template not specified]
}

# loading templates
$tTemplates[^self.getTemplates[
#	$.add_to_hash(true)
]]

$hXSLTParams[^self.parseBlockParams[$TEMPLATES.[$iTemplateID].params]]]

^if(def $hXSLTParams.[content-type]){
	$self.CONTENT-TYPE[$hXSLTParams.content-type]
}

$result[^xdcBody.transform[$TEMPLATES_PATH/$TEMPLATES.[$iTemplateID].filename][$hXSLTParams]]

$iErrorObjectID($SITES.[$SITE_ID].error_object_id)

# changing response status if this is error object
^if($iErrorObjectID == $OBJECT_ID){
	$response:status(404)
}
#end @transformDocument[]



###########################################################################
#	Result: string
@printDateTime[dtBody]
$result[^dtBody.sql-string[]]
#end @printDateTime[]
